import { programs, shaders } from '../shaders/webgl2samples/';

declare let amdRequire: any;

let monacoEditor: monaco.editor.IStandaloneCodeEditor;
let monacoEditor1: monaco.editor.IStandaloneCodeEditor;
let select: HTMLSelectElement;
let select_program: HTMLSelectElement;
let select_is_program: HTMLSelectElement;
let select_target: HTMLSelectElement;

const select_targetV = {
    "GLSL转换为WGSL": "glsl2wgsl",
    "升级到GLSL300": 'glslup300',
    "升级到GLSL450": 'glslup450',
};
const select_targetV1 = {
    "GLSL转换为WGSL": "glsl2wgslProgram",
    "升级到GLSL300": 'glslup300Program',
    "升级到GLSL450": 'glslup450Program',
};

const select_is_programV = {
    "单文件": false,
    "程序": true,
};

initMonaco(async () =>
{
    initlist();
    await initViewer();

    showShader();
});

function initlist()
{
    select_is_program = document.getElementById('select_is_program') as HTMLSelectElement;
    Object.keys(select_is_programV).forEach((i) =>
    {
        const option = document.createElement('option');
        option.value = i;
        option.appendChild(document.createTextNode(i));
        select_is_program.appendChild(option);
    });
    select_is_program.onchange = showShader;
    //
    select = document.getElementById('select') as HTMLSelectElement;
    Object.keys(shaders).forEach((i) =>
    {
        const option = document.createElement('option');
        option.value = i;
        option.appendChild(document.createTextNode(i));
        select.appendChild(option);
    });
    select.onchange = showShader;

    //
    select_program = document.getElementById('select_program') as HTMLSelectElement;
    Object.keys(programs).forEach((i) =>
    {
        const option = document.createElement('option');
        option.value = i;
        option.appendChild(document.createTextNode(i));
        select_program.appendChild(option);
    });
    select_program.onchange = showShader;

    //
    select_target = document.getElementById('select_target') as HTMLSelectElement;
    Object.keys(select_targetV).forEach((i) =>
    {
        const option = document.createElement('option');
        option.value = i;
        option.appendChild(document.createTextNode(i));
        select_target.appendChild(option);
    });
    select_target.onchange = showCode1;
}

function showShader()
{
    if (select_is_programV[select_is_program.value])
    {
        select.hidden = true;
        select_program.hidden = false;
    }
    else
    {
        select.hidden = false;
        select_program.hidden = true;
    }

    showCode();
    showCode1();
}

function initMonaco(callback: () => void)
{
    //
    amdRequire.config({ paths: { vs: 'monaco-editor/min/vs' } });
    amdRequire(['vs/editor/editor.main'], () =>
    {
        monacoEditor = monaco.editor.create(document.getElementById('container'), {
            model: null,
            formatOnType: true,
        });
        monacoEditor1 = monaco.editor.create(document.getElementById('container1'), {
            model: null,
            formatOnType: true,
        });
        window.onresize = function ()
        {
            monacoEditor.layout();
            monacoEditor1.layout();
        };
        callback();
    });
}

const vertex_fragment = '\n---------------------顶点片段分割线--------------------\n';

function showCode()
{
    let code = shaders[select.value];

    if (select_is_programV[select_is_program.value])
    {
        const { vertex, fragment } = programs[select_program.value];

        code = vertex + vertex_fragment + fragment;
    }

    const oldModel = monacoEditor.getModel();
    const newModel = monaco.editor.createModel(code, 'glsl');
    monacoEditor.setModel(newModel);
    if (oldModel) oldModel.dispose();

    monacoEditor.onDidChangeModelContent(() =>
    {
        showCode1();
    });
}

async function showCode1()
{
    const code = monacoEditor.getValue();

    let result: string;

    try
    {
        if (select_is_programV[select_is_program.value])
        {
            const [vertex, fragment] = code.split(vertex_fragment);
            const newProgram = await globalThis[select_targetV1[select_target.value]]({ vertex, fragment });

            result = newProgram.vertex + vertex_fragment + newProgram.fragment;

            if (newProgram.layoutInfo)
            {
                result += '\n---------------------布局信息分割线--------------------\n'
                    + JSON.stringify(newProgram.layoutInfo, null, '\t').replace(/[\n\t]+([\d\.e\-\[\]]+)/g, '$1');
            }
        }
        else
        {
            const result0 = await globalThis[select_targetV[select_target.value]](code);
            result = result0.code;
        }
    }
    catch (error)
    {
        result = error.message;
        console.warn(error);
    }

    const oldModel = monacoEditor1.getModel();
    const newModel = monaco.editor.createModel(result, 'glsl');
    monacoEditor1.setModel(newModel);
    if (oldModel) oldModel.dispose();
}

async function initViewer()
{
    const p = new Promise((resolve) =>
    {
        const viewer = document.getElementById('viewer') as HTMLIFrameElement;
        viewer.src = './src/index.html';

        viewer.onload = async () =>
        {
            window['initGlsl2wgsl'] = viewer.contentWindow['initGlsl2wgsl'];
            window['glsl2wgsl'] = viewer.contentWindow['glsl2wgsl'];
            window['glslup300'] = viewer.contentWindow['glslup300'];
            window['glslup450'] = viewer.contentWindow['glslup450'];

            window['glsl2wgslProgram'] = viewer.contentWindow['glsl2wgslProgram'];
            window['glslup300Program'] = viewer.contentWindow['glslup300Program'];
            window['glslup450Program'] = viewer.contentWindow['glslup450Program'];

            await window['initGlsl2wgsl']();

            resolve(0);
        };
    });

    return p;
}
